var web = web || {};
web.LunarCalendar = Class.create(); 
web.LunarCalendar.prototype = {
	initialize: function() {	
		this.lunarInfo = new Array(
		0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,
		0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,
		0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,
		0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,
		0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,
		0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0,
		0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,
		0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6,
		0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,
		0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,
		0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,
		0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,
		0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,
		0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,
		0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0);
		
		this.days = new Array('初一','初二','初三','初四','初五','初六','初七','初八','初九','初十','十一','十二','十三','十四','十五','十六','十七','十八','十九','二十','廿一','廿二','廿三','廿四','廿五','廿六','廿七','廿八','廿九','三十');
		this.months = new Array('正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '腊');
		this.animals = new Array('鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪');
		this.Gan = new Array('甲','乙','丙','丁','戊','己','庚','辛','壬','癸');
		this.Zhi = new Array('子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥');
		this.feast = {'1-1':'春节','1-15':'元宵节','5-5':'端午节','7-7':'七夕','8-15':'中秋节','9-9':'重阳节','12-8':'腊八','12-23':'小年', '12-30':'除夕'};
	},
	_yearDays:function(y) {
	   var i, sum = 348
	   for(i=0x8000; i>0x8; i>>=1) sum += (this.lunarInfo[y-1900] & i)? 1: 0;
	   return(sum+this._leapDays(y));
	},
	_leapDays:function(y) {
	   if( this._leapMonth(y) ) return((this.lunarInfo[y-1900] & 0x10000)? 30: 29);
	   else return(0);
	},
	_leapMonth:function(y) {
		return(this.lunarInfo[y-1900] & 0xf);
	},
	_monthDays:function(y, m) {
		return( (this.lunarInfo[y-1900] & (0x10000>>m))? 30: 29 );
	},
	getLunarDayInfo: function(solarDate) {
		var i, leap=0, temp=0;
		var utcDate = new Date(1900,0,31);
		var offset = (solarDate - utcDate)/86400000;
	
		for(i=1900; i<2050 && offset>0; i++) {
			temp = this._yearDays(i);
			offset -= temp;
		}
	
		if(offset<0) {
			offset += temp;
			i--;
		}
		
		var _lunarDays = {year:i, isLeap:false, isFeast:false, month:0, day:0};	
		
		leap = this._leapMonth(i);
		for(i=1; i<13 && offset>0; i++) {
			if (leap>0 && i==(leap+1) && _lunarDays.isLeap==false) { 
				--i; 
				_lunarDays.isLeap = true; 
				temp = this._leapDays(_lunarDays.year);
			 } else
				temp = this._monthDays(_lunarDays.year, i); 
			 
			if (_lunarDays.isLeap==true && i==(leap+1)) 
				_lunarDays.isLeap = false;
			offset -= temp;
		}
	
		if(offset==0 && leap>0 && i==leap+1) {
			if (_lunarDays.isLeap) {
				_lunarDays.isLeap = false;
			} else { 
				_lunarDays.isLeap = true; 
				--i; 
			}
		}
		
		if (offset<0) { 
			offset += temp; 
			--i; 
		}
		
		_lunarDays.month = i;
		_lunarDays.day = offset + 1;
		if (this.feast[_lunarDays.month+'-'+_lunarDays.day]) _lunarDays.isFeast = true;
		
		return _lunarDays;
	},
	getYearCyclical: function(n) {
	   return(this.Gan[n%10] + this.Zhi[n%12]);
	},
	getYearAnimal: function(y) {
		return this.animals[(y-4)%12];
	},
	getLunarDayFeastName: function(lunarDay) {
		if ( lunarDay.isFeast )
			return this.feast[lunarDay.month +'-'+ lunarDay.day];
		else
			return '';
	},
	getLunarDayName: function(lunarDay) {
		return  this.days[lunarDay.day-1];
	},
	formatLunarDay: function(lunarDay) {
		var _str = '农历 ';
		_str += this.getYearAnimal(lunarDay.year) +'年 &#8226; '+ this.getYearCyclical( lunarDay.year-1900+36 )+ ' &#8226; ';
		if (lunarDay.isLeap) _str += '润';
		_str +=this.months[lunarDay.month-1] +'月';
		_str += this.days[lunarDay.day-1];
		return _str;
	}
}

web.Calendar = Class.create(); 
web.Calendar.prototype = {
	initialize: function(options) {
		var defaults = {
			format: 'YYYY-MM-DD',
			isShowTime: 1
		};

		this.settings = $.extend(defaults, options);
		
		this.input = null;
		this.element = null;
		this.calendar = null;
		this.year = null;
		this.month = null;
		this.days = null;
		this.info = null;
		this.toToday = null;
		this.lunar = new web.LunarCalendar();
		
		this.currently = null;
		this.curMonthTerm = new Array();
		this.selected = null;
		this.today = new Date();
		
		this.limitMin = 0;
		this.limitMax = 0;
		
		this.monthDays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		this.feast = {'1-1':'元旦','2-14':'情人节','3-8':'妇女节','4-1':'愚人节','4-5':'清明节','5-1':'劳动节','6-1':'儿童节','8-1':'建军节','9-10':'教师节','10-1':'国庆节','12-25':'圣诞节'};
		this.termName = new Array('小寒','大寒','立春','雨水','惊蛰','春分','清明','谷雨','立夏','小满','芒种','夏至','小暑','大暑','立秋','处暑','白露','秋分','寒露','霜降','立冬','小雪','大雪','冬至');
		this.termVal = new Array(0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758);
	},
	bind: function(elem) {
		var _this = this;
		if (0 == elem.size()) return;
		this.element = elem;
		this.input = this.element.children('input');
		if( 0 == this.input.size()) return;
		
		//if (min_date) this.limitMin = this._getUTC(min_date);
		//if (max_date) this.limitMax = this._getUTC(max_date);
		
		this.element.bind('click', function(event) {
			_this._init();
			_this._show();
		});
	},
	_init: function() {		
		this.selected = this.today;
		if (this._isDate(this.input.val())) {
			var _temp = this.input.val().split('-');
			this.selected = new Date(_temp[0], _temp[1]-1, _temp[2]);
		}
		this.currently = this.selected;
	},
	_show: function(input) {
		if (!this.calendar) this._createCalendarPanel();
				
		var _offset = this.element.offset();
		this.calendar.css({left:_offset.left, top:_offset.top+this.element.height()+3});
		this._showMonth();
		this.calendar.show();
	},
	_hide: function() {
		this.calendar.hide();
	},
	_strPad: function(str) {
		var _str = '0'+ str;
		if(_str.length > 2) {
			return str;
		} else {
			return _str;
		}
	},
	_setInputValue: function(date) {
		var _d = new Date(date.year, date.month, date.day);
		var y = _d.getFullYear(), m = _d.getMonth(), d = _d.getDate(),
		h = _d.getHours(), j = _d.getMinutes(), s = _d.getSeconds();
		
		var result = this.settings.format
		.replace('yyyy', y).replace('yy', (y +'').substr(2))
		.replace('MM', this._strPad(m)).replace('M', m)
		.replace('dd', this._strPad(d)).replace('d', d)
		.replace('hh', this._strPad(h)).replace('h', h)
		.replace('mm', this._strPad(j)).replace('m', j)
		.replace('ss', this._strPad(s)).replace('s', s);
		
		this.input.val(result);
	},
	_showMonth: function() {
		var _this = this;
		var _year = this.currently.getFullYear();
		var _month = this.currently.getMonth();
		var _days = this._getMonthDays(_year, _month);
		this._getMonthTerm(_year, _month);
		var _firstDay = new Date(_year, _month, 1);
		
		this.days.html('');
		this.days.append('<ul class="clearfix"></ul>'); 
		var _ul = this.days.find('ul');
		
		this.year.attr('value', _year);
		this.month.attr('value', _month+1);
		if (_year==this.today.getFullYear() && _month==this.today.getMonth()) this.toToday.hide();
		else this.toToday.show();
		
		var _lunarDays = new Array();
		var _solarDays = new Array();
		
		var _day = 0;
		var _class = '';
		var _sy = this.selected.getFullYear(), _sm = this.selected.getMonth(), _sd = this.selected.getDate();
		var _li = null,_date=null;
		for ( var i=0; i<_firstDay.getDay(); i++) _ul.append('<li class="empty"></li>'); 
		for (var i=0; i<_days; i++) {
			_day = i+1;
			
			_date = new Date(_year, _month, _day); 
			_solarDays.push( this._getDayInfo(_year, _month, _day) );
			_lunarDays.push( this.lunar.getLunarDayInfo(_date));
			
			if (_sy ==_year && _sm==_month && _sd==_day) {
				this.info.html(_this.lunar.formatLunarDay(_lunarDays[i]));
				_class = ' class="selected"';
			}
			
			if (this.limitMin && this.limitMin< _date.getTime()) _class = ' class="disable"';
			if (this.limitMax && this.limitMax>_date.getTime()) _class = ' class="disable"';
			
			_li = $('<li'+ _class +'><p class="day">'+ _day +'</p>'+ this._getCurDayShowName(_solarDays[i], _lunarDays[i]) +'</li>');
			_li.appendTo(_ul); 
			_class = '';
			
			_li.bind('mouseover', {lunarDay:_lunarDays[i]}, function(event) {																		 
				_this.info.html(_this.lunar.formatLunarDay(event.data.lunarDay));
			});
			_li.bind('click', {solarDay:_solarDays[i]}, function(event) {	
				var _date = event.data.solarDay;
				if ($(this).hasClass('disable')) return;
				
				_this._setInputValue(_date);
				_this._hide();
			});														 
		}
	},
	_getCurDayShowName: function(solarDay, lunarDay) {
		if (lunarDay.isFeast) return '<p class="lunar_feast">'+ this.lunar.getLunarDayFeastName(lunarDay) +'</p>';
		else if ( solarDay.isFeast ) return '<p class="solar_feast">'+ this._getDayFeastName(solarDay) +'</p>';
		else if ( solarDay.term > 0 ) return '<p class="solar_term">'+ this.termName[solarDay.term] +'</p>';
		else return '<p class="normal">'+ this.lunar.getLunarDayName(lunarDay) +'</p>';
	},
	_createCalendarPanel: function() {
		var _this = this;
		var _calendar = '<div id="div_calendar_panel" class="calendar">' +
						'	<div class="calendar_top"><em title="上一月" go="pre">&lt;&lt;</em>公元<select go="year"></select>年<select go="month"></select>月<em title="下一月" go="next">&gt;&gt;</em><em title="返回到当月" go="today" style="display:none;">今天</em></div>' +
						'	<div class="calendar_week"><ul class="clearfix"><li><b>日</b></li><li>一</li><li>二</li><li>三</li><li>四</li><li>五</li><li><b>六</b></li></ul></div>' +
						'	<div class="calendar_days"></div>' +
						'	<div class="calendar_info"></div>' +
						'</div>';
		$(document.body).append(_calendar);
		this.calendar = $('#div_calendar_panel');
		this.days = this.calendar.children(".calendar_days");
		this.info = this.calendar.children(".calendar_info");
		var _top = this.calendar.children(".calendar_top");
		this.toToday = _top.children("em[go='today']");
		this.year = _top.children("select[go='year']");
		this.month = _top.children("select[go='month']");

		for (var i=this.today.getFullYear()-5; i<this.today.getFullYear()+5; i++) {
			$('<option value="'+ i +'">'+ i +'</option>').appendTo( this.year );
		}
		for (var i=1; i<=12; i++) {
			$('<option value="'+ i +'">'+ i +'</option>').appendTo( this.month );
		}
		this.calendar.bind('mouseup', function(event){
			event.stopPropagation();								   
		});
		$(document).bind('mouseup', function(){
			_this._hide();							 
		});
		
		this.year.bind('change', function(){
			var _self = $(this);
			var _year = _self.val();
			var _month = _this.currently.getMonth();
			_this.currently = new Date(_year, _month, 1);
			_this._show();
		});
		this.month.bind('change', function(){
			var _self = $(this);
			var _year = _this.currently.getFullYear();
			var _month = _self.val();
			_this.currently = new Date(_year, _month-1, 1);
			_this._show();
		});
		_top.children("em").bind('mouseup', function() {  
			var _self = $(this);
			var _year = _this.currently.getFullYear();
			var _month = _this.currently.getMonth();
			var _go = _self.attr('go');
			
			if (_go== 'pre') {
				if (0==_month) {_year--; _month=11;}
				else _month--;
				_this.currently = new Date(_year, _month, 1);
			} else if(_go== 'next') {
				if (11==_month) {_year++; _month=0;}
				else _month++;
				_this.currently = new Date(_year, _month, 1);
			} else if(_go== 'today') {
				_this.currently = _this.today;
			}
			
			_this._show();
		});
	},
	_getDayFeastName: function(solarDay) {
		if ( solarDay.isFeast )
			return this.feast[solarDay.month +'-'+ solarDay.day];
		else
			return '';
	},
	_getTerm: function(y, i) {
		return new Date((31556925974.7 * (y - 1900) + this.termVal[i] * 60000 ) + Date.UTC(1900, 0, 6, 2, 5)).getUTCDate();
	},
	_getMonthTerm: function(y, m) {
		this.curMonthTerm = [];
		this.curMonthTerm.push([this._getTerm(y, m*2), m*2]);
		this.curMonthTerm.push([this._getTerm(y, m*2+1), m*2+1]);
	},
	_getDayInfo: function(y, m, d) {
		m = m + 1;
		var _solarDay = {isFeast:false, term:0, year:y, month:m, day:d};
		if (this.feast[m +'-'+ d]) _solarDay.isFeast = true;
		if (this.curMonthTerm[0][0] == d) _solarDay.term = this.curMonthTerm[0][1];
		if (this.curMonthTerm[1][0] == d) _solarDay.term = this.curMonthTerm[1][1];
		return _solarDay;
	},
	_getMonthDays: function(y, m) {
	   if (1 == m) {
		  return(((y%4 == 0) && (y%100 != 0) || (y%400 == 0))? 29: 28);
	   } else {
		  return(this.monthDays[m]);
	   }
	},
	_isDate: function(date) {
		var _pattern = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
		if (!date.match(_pattern)) return false;
		
		//var _n = new Date(date.replace(/\-/g, '/'));    
		//var _s = date.split(/[-/:]/);
		
		var _s = date.split('-'); _s[1]=_s[1]-1;
		var _d = new Date(_s[0], _s[1], _s[2]);
		if (_s[0]!=_d.getFullYear() || _s[1]!=_d.getMonth() || _s[2]!=_d.getDate()) {
			return false;
		}
		return true;
	},
	_isDateTime: function(dateTime) {
		var _pattern = /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
		var _r = dateTime.match(_pattern);
		if (_r==null) return false;
		
		_r[2]=_r[2]-1;
		var _d = new Date(_r[1], _r[2], _r[3], _r[4], _r[5], _r[6]);
		if (_d.getFullYear()!=_r[1]) return false;
		if (_d.getMonth()!=_r[2]) return false;
		if (_d.getDate()!=_r[3]) return false;
		if (_d.getHours()!=_r[4]) return false;
		if (_d.getMinutes()!=_r[5]) return false;
		if (_d.getSeconds()!=_r[6]) return false; 
		
		return true;
	},
	_getUTC: function(date) {
		if (!this._isDate(date)) return 0;
		var _t = date.split('-');
		return Date.UTC(_t[0], _t[1]-1, _t[2]);
	}
};

(function($){  
	$.fn.calendar = function(options){ 
		return this.each(function(){
			var _calendar = new web.Calendar(options);
			_calendar.bind($(this));
		});
	}
})(jQuery); 